/*
 * Author: Honrun
 */
#include "stm32f4xx_hal.h"
#include "DevicesDelay.h"
#include "DevicesFlash.h"
#include "DevicesSPI.h"
#include "DevicesSPIFlash.h"



void vSPIFlashInit(void)
{
    uint8_t ucCmd = 0;

    vSPI2Init();

    SPI2_NSS_ENABLE();
    ucCmd = RESET_ENABLE_CMD;
    cSPI2WriteDatas(&ucCmd, 1);

    ucCmd = RESET_MEMORY_CMD;
    cSPI2WriteDatas(&ucCmd, 1);
    SPI2_NSS_DISABLE();
}


int8_t cSPIFlashErases(uint32_t uiAddress)
{
    uint8_t ucCmd = SUBSECTOR_ERASE_CMD, ucAddress[3] = {0};
    int8_t cError = 0;

    /* 等待Flash退出忙状态 */
    if(ucSPIFlashReadStatus(0x01) == 0x01)
        return -11;

    uvSPIFlashEnableWrite();

    /* 等待Flash退出忙状态 */
    if(ucSPIFlashReadStatus(0x01) == 0x01)
        return -12;

    SPI2_NSS_ENABLE();

    ucAddress[0] = uiAddress >> 16;
    ucAddress[1] = uiAddress >> 8;
    ucAddress[2] = uiAddress;

    cError |= cSPI2WriteDatas(&ucCmd, 1);
    cError |= cSPI2WriteDatas(ucAddress, 3);

    SPI2_NSS_DISABLE();

    return cError;
}

int8_t cSPIFlashWritePage(uint32_t uiAddress, uint8_t *pucDatas, uint32_t uiLength)
{
    uint8_t ucCmd = PAGE_PROG_CMD, ucAddress[3] = {0};
    int8_t cError = 0;

    /* 等待Flash退出忙状态 */
    if(ucSPIFlashReadStatus(0x01) == 0x01)
        return -1;

    uvSPIFlashEnableWrite();

    /* 等待Flash退出忙状态 */
    if(ucSPIFlashReadStatus(0x01) == 0x01)
        return -2;

    SPI2_NSS_ENABLE();

    ucAddress[0] = uiAddress >> 16;
    ucAddress[1] = uiAddress >> 8;
    ucAddress[2] = uiAddress;

    cError |= cSPI2WriteDatas(&ucCmd, 1);
    cError |= cSPI2WriteDatas(ucAddress, 3);

    /* 写入数据 */
    cError |= cSPI2WriteDatas(pucDatas, uiLength);

    SPI2_NSS_DISABLE();

    return cError;
}

int8_t cSPIFlashWriteDatas(uint32_t uiAddress, uint8_t *pucDatas, uint32_t uiLength)
{
    uint32_t uiLengthTemp = 0;
    int32_t iLengthTemp = uiLength;
    int8_t cError = 0;

    /* Write Flash */
    while(iLengthTemp > 0)
    {
        if((uiAddress & 4095) == 0)
        {
            if(cSPIFlashErases(uiAddress) != 0)
            {
                cError |= 1;
                break;
            }
        }

        uiLengthTemp = (iLengthTemp > (256 - (uiAddress & 255))) ? (256 - (uiAddress & 255)) : iLengthTemp;

        if(cSPIFlashWritePage(uiAddress, pucDatas, uiLengthTemp) != 0)
        {
            cError |= 2;
            break;
        }

        uiAddress += uiLengthTemp;
        iLengthTemp -= uiLengthTemp;
        pucDatas += uiLengthTemp;
    }

    return cError;
}

int8_t cSPIFlashReadDatas(uint32_t uiAddress, uint8_t *pucDatas, uint32_t uiLength)
{
    uint32_t uiLengthTemp = 0;
    int32_t iLengthTemp = uiLength;
    uint8_t ucCmd = READ_CMD, ucAddress[3] = {0};
    int8_t cError = 0;


    /* Read Flash */
    while(iLengthTemp > 0)
    {
        uiLengthTemp = (iLengthTemp > (256 - (uiAddress & 255))) ? (256 - (uiAddress & 255)) : iLengthTemp;

        /* 等待Flash退出忙状态 */
        if(ucSPIFlashReadStatus(0x01) == 0x01)
            return -1;

        SPI2_NSS_ENABLE();

        ucAddress[0] = uiAddress >> 16;
        ucAddress[1] = uiAddress >> 8;
        ucAddress[2] = uiAddress;

        cError |= cSPI2WriteDatas(&ucCmd, 1);
        cError |= cSPI2WriteDatas(ucAddress, 3);

        if(cSPI2ReadDatas(pucDatas, uiLengthTemp) != 0)
        {
            cError |= 1;
            SPI2_NSS_DISABLE();
            break;
        }

        SPI2_NSS_DISABLE();

        uiAddress += uiLengthTemp;
        iLengthTemp -= uiLengthTemp;
        pucDatas += uiLengthTemp;
    }

    return cError;
}

uint32_t uiSPIFlashReadID(void)
{
    uint32_t uiID = 0;
    uint8_t ucCmd = READ_ID_CMD2;

    SPI2_NSS_ENABLE();

    cSPI2WriteDatas(&ucCmd, 1);

    cSPI2ReadDatas((uint8_t *)(&uiID), 3);

    SPI2_NSS_DISABLE();

    return uiID;
}

uint8_t ucSPIFlashReadStatus(uint32_t uiFlag)
{
    uint32_t uiTimeout = 10000;
    uint8_t ucCmd = READ_STATUS_REG_CMD, ucStatus = 0;

    /* 等待Flash状态 */
    while(--uiTimeout)
    {
        SPI2_NSS_ENABLE();

        cSPI2WriteDatas(&ucCmd, 1);
        cSPI2ReadDatas(&ucStatus, 1);

        SPI2_NSS_DISABLE();

        if((ucStatus & uiFlag) != uiFlag)
            break;
    }

    return (ucStatus & uiFlag);
}

void uvSPIFlashEnableWrite(void)
{
    uint8_t ucCmd = WRITE_ENABLE_CMD;

    SPI2_NSS_ENABLE();

    cSPI2WriteDatas(&ucCmd, 1);

    SPI2_NSS_DISABLE();
}
